//---------------------------------------------------------------------
// <copyright file="CaseCqlBlock.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------

using System.Data.Mapping.ViewGeneration.Structures;
using System.Text;
using System.Collections.Generic;
using System.Data.Common.CommandTrees;
using System.Data.Common.CommandTrees.ExpressionBuilder;
using System.Data.Common.Utils;
using System.Diagnostics;

namespace System.Data.Mapping.ViewGeneration.CqlGeneration
{
    /// <summary>
    /// A class to capture cql blocks responsible for case statements generating multiconstants, i.e., complex types, entities, discriminators, etc.
    /// </summary>
    internal sealed class CaseCqlBlock : CqlBlock
    {
        #region Constructors
        /// <summary>
        /// Creates a <see cref="CqlBlock"/> containing the case statememt for the <paramref name="caseSlot"/> and projecting other slots as is from its child (input). CqlBlock with SELECT (slots),
        /// </summary>
        /// <param name="caseSlot">indicates which slot in <paramref name="slots"/> corresponds to the case statement being generated by this block</param>
        internal CaseCqlBlock(SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum)
            : base(slots, new List<CqlBlock>(new CqlBlock[] { child }), whereClause, identifiers, blockAliasNum)
        {
            m_caseSlotInfo = slots[caseSlot];
        }
        #endregion

        #region Fields
        private readonly SlotInfo m_caseSlotInfo;
        #endregion

        #region Methods
        internal override StringBuilder AsEsql(StringBuilder builder, bool isTopLevel, int indentLevel)
        {
            // The SELECT part
            StringUtil.IndentNewLine(builder, indentLevel);
            builder.Append("SELECT ");
            if (isTopLevel)
            {
                builder.Append("VALUE ");
            }
            Debug.Assert(m_caseSlotInfo.OutputMember != null, "We only construct member slots, not boolean slots.");
            builder.Append("-- Constructing ").Append(m_caseSlotInfo.OutputMember.LeafName);

            Debug.Assert(Children.Count == 1, "CaseCqlBlock can have exactly one child.");
            CqlBlock childBlock = Children[0];

            base.GenerateProjectionEsql(builder, childBlock.CqlAlias, true, indentLevel, isTopLevel);

            // The FROM part: FROM (ChildView) AS AliasName
            builder.Append("FROM (");
            childBlock.AsEsql(builder, false, indentLevel + 1);
            StringUtil.IndentNewLine(builder, indentLevel);
            builder.Append(") AS ").Append(childBlock.CqlAlias);

            // Get the WHERE part only when the expression is not simply TRUE.
            if (false == BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                StringUtil.IndentNewLine(builder, indentLevel);
                builder.Append("WHERE ");
                this.WhereClause.AsEsql(builder, childBlock.CqlAlias);
            }

            return builder;
        }

        internal override DbExpression AsCqt(bool isTopLevel)
        {
            Debug.Assert(m_caseSlotInfo.OutputMember != null, "We only construct real slots not boolean slots");

            // The FROM part: FROM (childBlock)
            Debug.Assert(Children.Count == 1, "CaseCqlBlock can have exactly one child.");
            CqlBlock childBlock = this.Children[0];
            DbExpression cqt = childBlock.AsCqt(false);

            // Get the WHERE part only when the expression is not simply TRUE.
            if (!BoolExpression.EqualityComparer.Equals(this.WhereClause, BoolExpression.True))
            {
                cqt = cqt.Where(row => this.WhereClause.AsCqt(row));
            }

            // The SELECT part.
            return cqt.Select(row => GenerateProjectionCqt(row, isTopLevel));
        }
        #endregion
    }
}
